package TAIC.Classifier;
import java.util.*;
import java.io.*;

import TAIC.test.TestMode;

/**
 Estimate P(f|c), P(f|v) and then calculate KL-divergence between them 
 P(f|c)=P(f|v)P(v|w)P(w|c) 
 P(f|v)= [ n(f)+1 ]  /  [ n(v)+|f| ]
 P(v|w) = 1 
 P(w|c) = n(image of word w) / |total images|
 */
public class RiskMinimization extends Classifier {
	static final int VECSIZE = 800 ; 
	int classes = TestMode.para.getParaInt( "MaxClass" ) , totalPic = 0 ;
	Vector< double [] > [] p_f_v ;  //  p [ classed ][ pic ][ feature ]  
	double [][] center ; 
	int n_w_c [][] ; 
	
	public static void main ( String str [] )  {
		RiskMinimization rm = new RiskMinimization ( ) ;  
		rm.train ( "trainset") ;
		System.out.println( rm.test ( "testset" )); 
	}

	public void train ( String trainFile ) {
		int keys = 0 ; 
		
		center = new double [ classes ][ VECSIZE ] ; 
		try {			
			Scanner scanner ;
			if ( ! isPipe() )  scanner = new Scanner ( new File ( trainFile ) ) ;
			else {
				scanner = new Scanner ( new ByteArrayInputStream( trainPipe ) ) ;
			}
			Scanner picProb = new Scanner ( new File ( "picProb.txt" )); 

			int len = 0 ; 
			p_f_v = new Vector [ classes ] ;
			for ( int i = 0; i < classes ; i ++ ) p_f_v[ i ] = new Vector < double []> () ;
			while ( scanner.hasNext() ) {
				len ++ ; 
				String str = scanner.next () ;
				double [] p = new double [ VECSIZE ] ;
				int className = translateClass ( str );
				get_f( scanner.nextLine (), p ) ;
				double prob  = picProb.nextDouble() ;
				p_f_v [ className ].add( p );
				for ( int k = 0 ; k < VECSIZE ; k ++ ) 
					center [ className ][ k ] += p[ k ] * prob ; 
			}
			
		}
		catch ( Exception e ) {
			e.printStackTrace() ;
		}
		
		for ( int i = 0 ; i < classes ;i ++ )  divergence.normalize( center [ i ]) ; 
	}
	
	public double test ( String testFile ) {
		int total = 0 , correct = 0 ; 
		try { 
			Scanner scanner ;
			if ( ! isPipe() )  scanner = new Scanner ( new File ( testFile ) ) ;
			else {
				scanner = new Scanner ( new  ByteArrayInputStream ( testPipe ) ) ;
			}	
			while ( scanner.hasNext() ) {
				String str = scanner.next ();
				int thisClass = translateClass ( str ) ;
				double p [ ] = new double [ VECSIZE ] ;
				get_f ( scanner.nextLine() , p ) ;
				int judge = findMin ( p ) ; 
				if ( judge == thisClass ) correct ++ ;
				total ++ ;
			}
		}
		catch ( Exception e ) {
			e.printStackTrace()  ; 
		}		
		if ( total == 0 ) return 0.0 ;
		else return (double)correct/ total ; 
	}

	private int findMin ( double [] p ) {
		double min = 1e5 ; 
		int best = 0 ; 
		for ( int i = 0 ; i < classes ; i ++ ) {
			double temp = divergence.cale( center [ i ] , p ) ;
			//System.out.print ( temp + " " ) ; 
			if ( temp < min ) {
				min = temp ; 
				best = i ;
			}
		}
		//System.out.println ("\t\t" + best ); 
		return best ; 
	}
		
	private void get_f ( String buffer , double [] p) {
		Scanner line = new Scanner ( buffer ) ;
		double total = 0.0 ; 
		while ( line.hasNext() ) {
			String str = line.next() ;
			int vecNo = Integer.valueOf( str.substring(0, str.indexOf(':'))) ;
			int value = Integer.valueOf( str.substring(str.indexOf(':') + 1 ) );					
			p [ vecNo - 1 ] += value  ;
			total += value ;
		}
		divergence.normalize( p ) ; 		
	}
	
	static Divergence divergence = cFact.getDivergence( cConfig.get( "divergence")) ; 

		//new Cosine () ; // new KL_Divergence () ;
}
